package stti.canal.telefonia;

import java.net.Socket;

import stti.model.Constantes;
import stti.model.to.TelefonoTO;
import stti.util.log.*;


/**
 * <b> EJB de servicios de Telefonia IP</b>
 * <p>
 * Servicios de interaccion con servidor de telefonia IP Asterisk
 * </p>
 * 
 * Registro de versiones:<ul>
 * <li>1.0 (26/10/2011): Ivan Kruze : 	Versi�n inicial</li>
 * </ul>
 *
 * <p>
 * <b>Todos los derechos reservados Strategica TI</b>
 * </p>
 */
public class TelefoniaIP {

	/**
	 * Socket para conexi�n hacia Asterisk
	 */
	private Socket AMI; 
	
	/**
	 * Instancia de comunicaci�n hacia Asterisk
	 */
	private TelefoniaIPListener AMI_Listener;
	
	/**
	 * Parametros de configuraci�n Socket Asterisk
	 */
	private String AMI_Username = "";
	private String AMI_Secret = "";
	private String AMI_IP = "";
	private int AMI_Port = 5038;
	
	private static final long serialVersionUID = 1;
    private static Logger log = Logger.getLogger(TelefoniaIP.class);


	public TelefoniaIP() {
		// TODO Crear lista para IVR
		if (!getConfiguracion())
		{
			log.error("[ejbCreate] No se pudo obtener la configuracion desde tabla de parametros");
		}
		if (!conectarSocketAMI())
		{
			log.error("[ejbCreate] No se pudo establecer la conexion hacia el servidor Asterisk");
		}
		log.debug("[ejbCreate] EJB Creado Correctamente");
	}
	
	
	/**
	 * M�todo privado para cargar la configuraci�n desde la tabla de par�metros
	 * <P>
	 * 
	 * Registro de versiones:<ul>
	 * <li>1.0 26/10/2011 Ivan Kruze : versi�n inicial</li>
	 * </ul></P>
	 * 
	 * @return Variable booleana indicando si se pudo obtener la configuraci�n desde la tabla de par�metros
	 * @since 1.0
	 */
	private boolean getConfiguracion()
	{
		boolean resultado = true;
		try
		{
			log.debug("[getConfiguracion] Intentando obtener valores desde tabla de parametros");
			//AMI_IP = TablaValores.getValor(TelefoniaIPConstantes.TABLA_PARAMETROS_TELEFONIA_IP, "Asterisk", "IP");
			//AMI_Port = Integer.parseInt(TablaValores.getValor(TelefoniaIPConstantes.TABLA_PARAMETROS_TELEFONIA_IP, "Asterisk", "Puerto"));
			//AMI_Username = TablaValores.getValor(TelefoniaIPConstantes.TABLA_PARAMETROS_TELEFONIA_IP, "Asterisk", "username");
			//AMI_Secret = TablaValores.getValor(TelefoniaIPConstantes.TABLA_PARAMETROS_TELEFONIA_IP, "Asterisk", "secret");
			AMI_IP = "www.strategicati.cl";
			AMI_Port = 5038;
			AMI_Username = "admin";
			AMI_Secret = "amp2010clavesegura";
			log.debug("[getConfiguracion] Configuracion completa desde tabla de parametros");
		} catch (Exception e)
		{
			resultado = false;
			log.debug("[getConfiguracion] No se pudo obtener la configuracion desde la tabla de parametros");
		}
		return resultado;
	}
	
	/**
	 * M�todo privado para establecer la conexi�n hacia el servidor Asterisk
	 * <P>
	 * 
	 * Registro de versiones:<ul>
	 * <li>1.0 26/10/2011 Ivan Kruze : versi�n inicial</li>
	 * </ul></P>
	 * 
	 * @return Variable booleana indicando si se pudo establecer la conexi�n o no
	 * @since 1.0
	 */
	private boolean conectarSocketAMI()
	{
		boolean resultado = true;
		try
		{
			log.debug("[conectarSocketAMI] Estableciendo la conexi�n al servidor de telefonia");
			AMI = new Socket(this.AMI_IP, this.AMI_Port);
			log.debug("[conectarSocketAMI] Conectado");
			log.debug("[conectarSocketAMI] Creando instancia de listener");
			
			AMI_Listener = new TelefoniaIPListener(AMI, AMI_Username, AMI_Secret);
			AMI_Listener.start();
			int a = 0;
			while ((AMI_Listener.isRunning()) && (!AMI_Listener.isLoggedIn()))
			{
				//log.info("Listener "+AMI_Listener.isRunning()+" Logged: "+AMI_Listener.isLoggedIn());
				System.out.print(".");
				
				// Espero
			}
			log.debug("[conectarSocketAMI] Listener Ok");
			
		} catch (Exception e)
		{
			resultado = false;
			log.debug("[conectarSocketAMI] No se pudo establecer la conexi�n al servidor de telefonia");
			
		}
		
		return resultado;
	}
	
	/**
	 * M�todo privado para cerrar la sesi�n hacia Asterisk
	 * <P>
	 * 
	 * Registro de versiones:<ul>
	 * <li>1.0 26/10/2011 Ivan Kruze : versi�n inicial</li>
	 * </ul></P>
	 * 
	 * @since 1.0 
	 */
	public void logoff()
	{
		if (AMI_Listener != null)
		{
			AMI_Listener.logoff();
		}
		try
		{
			AMI.close();
		} catch (Exception e)
		{
			AMI = null;
			log.debug("[logoff] No se pudo cerrar el socket, se destruye la instancia.");
		}
	}
	
	/**
	 * M�todo privado para corregir el formato del texto que se utilizar� para secuencias de Text2Speech
	 * <P>
	 * 
	 * Registro de versiones:<ul>
	 * <li>1.0 27/10/2011 Ivan Kruze : versi�n inicial</li>
	 * </ul></P>
	 * 
	 * @param entrada Texto original
	 * @return String texto corregido
	 * @since 1.0
	 */
	private String corrigeTexto(String entrada)
	{
		String salida = entrada;
		log.debug("[corrigeTexto] Texto Original: '"+entrada+"'");
		salida = entrada.replaceAll(",", "  ");
		salida = entrada.replaceAll(".", "    ");
		salida = entrada.replaceAll("'", "");
		salida = entrada.replaceAll("\"", "");
		/* salida = StringUtil.reemplazaTodo(salida, "�", "a");
		salida = StringUtil.reemplazaTodo(salida, "�", "e");
		salida = StringUtil.reemplazaTodo(salida, "�", "i");
		salida = StringUtil.reemplazaTodo(salida, "�", "o");
		salida = StringUtil.reemplazaTodo(salida, "�", "u");
		salida = StringUtil.reemplazaTodo(salida, "�", "A");
		salida = StringUtil.reemplazaTodo(salida, "�", "E");
		salida = StringUtil.reemplazaTodo(salida, "�", "I");
		salida = StringUtil.reemplazaTodo(salida, "�", "O");
		salida = StringUtil.reemplazaTodo(salida, "�", "U");
		salida = StringUtil.reemplazaTodo(salida, "�", "gn");
		salida = StringUtil.reemplazaTodo(salida, "�", "gn"); */
		log.debug("[corrigeTexto] Texto Corregido: '"+salida+"'");
		
		return salida;
	}
	
	/**
     * M�todo para ejecutar una llamada telef�nica entre dos n�meros p�blicos o anexos
     * <P>
     * 
     * Registro de versiones:<ul>
     * <li>1.0 26/10/2011 Ivan Kruze : versi�n inicial</li>
     * </ul></P>
     *
     * @param numeroOrigen : Anexo o n�mero de telefon�a fija en formato banco para el origen de la llamada.
     * @param numeroDestino : Anexo o n�mero de tlefon�a fija en formato banco para el origen de la llamada.
     * @since 1.0
     */		
	public void llamadaTelefonica(TelefonoTO numeroOrigen, TelefonoTO numeroDestino)
	throws Exception
	{
		numeroOrigen.setOriginaLlamada(true);
		numeroDestino.setOriginaLlamada(false);
		log.debug("[llamadaTelefonica] Discando entre ("+numeroOrigen.toString()+") y ("+numeroDestino.toString()+")");
		if ((AMI_Listener != null) && (AMI_Listener.isRunning())) 
		{
			if (AMI_Listener.isLoggedIn())
			{
				if (!AMI_Listener.llamadaTelefonica(numeroOrigen.getNumeroTelefono(), numeroDestino.getNumeroTelefono()))
				{
					throw new Exception("No se pudo enviar la solicitud de llamada telef�nica");
				}
				while (AMI_Listener.getLastStatus() == Constantes.STATUS_IDLE)
				{
					// Espera
				}
				if (AMI_Listener.getLastStatus() == Constantes.STATUS_ERROR_INICIAR_LLAMADA)
				{
					throw new Exception("El n�mero de origen no es v�lido");
				}
				if (AMI_Listener.getLastStatus() == Constantes.STATUS_ERROR_ORIGEN_NO_CONTESTA)
				{
					throw new Exception("El n�mero de origen de la llamada no contesta");
				}
			}
			else
			{
				log.error("[llamadaTelefonica] No hay una sesi�n activa de manager para establecer la llamada");
			}
		}
		else
		{
			log.error("[llamadaTelefonica] No hay una instancia de Manager disponible para la llamada");
		}
	}
	
    /**
     * M�todo para consultar si un n�mero telef�nico est� participando de una conversaci�n en el servidor Asterisk
     * 
     * <P>
     * Registro de versiones:<ul>
     * <li>1.0 26/10/2011 Ivan Kruze : versi�n inicial</li>
     * </ul></P>
     * 
     *  @param numeroTelefono : Anexo o n�mero sobre el cual se consultar� si participa en una conversaci�n en Asterisk
     *  @return boolean Resultado si el telefono est� en uso o no
     *  @since 1.0
     */	
	public boolean consultaEstadoTelefono(String telefono)
	throws Exception
	{
		boolean respuesta = false;
		int codigoRespuesta = Constantes.STATUS_IDLE;
		String numeroCorregido = " "+telefono+" ";
		
		log.debug("[consultaEstadoTelefono] Iniciando consulta por telefono");
		if ((AMI_Listener != null) && (AMI_Listener.isRunning())) 
		{
			if (AMI_Listener.isLoggedIn())		
			{
				if (!AMI_Listener.consultaEstadoTelefono(telefono))
				{
					throw new Exception("No se pudo consultar por el estado del telefono");
				}			
				while ((codigoRespuesta = AMI_Listener.getLastStatus()) == Constantes.STATUS_IDLE)
				{
					// Espera
				}
				
				if (codigoRespuesta == Constantes.STATUS_RESPUESTA_COMPLETA)
				{
					String[] lista = AMI_Listener.getRespuesta();
					for (int i = 0; i < lista.length; i++)
					{
						if (lista[i].indexOf(numeroCorregido) > -1)
						{
							respuesta = true;
						}
					}
				}
			}
		}
		return respuesta;
	}
	
	/**
     * M�todo llamar a un n�mero y utilizar la herramienta de Text2Speech disponible en el servidor de telefon�a para sintentizar un texto
     * 
     * <P>
     * Registro de versiones:<ul>
     * <li>1.0 27/10/2011 Ivan Kruze : versi�n inicial</li>
     * </ul></P>
     * 
	 * @param telefono Destinatario de la llamada
	 * @param texto Texto a decir al destinatario de la llamada, se utiliza Festival o Loquendo segun la configuraci�n del servidor de telefon�a
	 * @return boolean Resultado si la operaci�n se pudo completar o no
	 * @since 1.0
	 */
	public boolean enviaTextoTelefono(TelefonoTO telefono, String texto)
	throws Exception
	{
		boolean resultado = false;
		String textoCorregido = corrigeTexto(texto);
		String idTexto = "";
		telefono.setOriginaLlamada(true);
		log.debug("[enviaTextoTelefono] Enviando solicitud Text2Speech a "+telefono);
		if ((AMI_Listener != null) && (AMI_Listener.isRunning())) 
		{
			if (AMI_Listener.isLoggedIn())		
			{
				TelefoniaIPConectorAPI conector = new TelefoniaIPConectorAPI();
				idTexto = conector.publicaTexto(textoCorregido);
				conector.cerrar();
				if (idTexto.length() > 0)
				{
					if (!AMI_Listener.enviaTextoTelefono(telefono.getNumeroTelefono(),idTexto))
					{
						throw new Exception("No se pudo enviar la solicitud de llamada");
					}
					while (AMI_Listener.getLastStatus() == Constantes.STATUS_IDLE)
					{
						// Espera
					}
					if (AMI_Listener.getLastStatus() == Constantes.STATUS_ERROR_INICIAR_LLAMADA)
					{
						throw new Exception("El n�mero de origen no es v�lido");
					}
					if (AMI_Listener.getLastStatus() == Constantes.STATUS_ERROR_ORIGEN_NO_CONTESTA)
					{
						throw new Exception("El n�mero de origen de la llamada no contesta");
					}					
				}
			}
		}
		return resultado;
	}
	
	/**
     * M�todo para ejecutar una llamada telef�nica entre dos n�meros p�blicos o anexos, cuando el tel�fono es levantado por quien origina la llamada se reproducir� un audio con el contenido del Texto de Introducci�n que se ha especificado, una vez finalizado se enviar� la llamada al segundo n�mero
     * <P>
     * 
     * Registro de versiones:<ul>
     * <li>1.0 28/10/2011 Ivan Kruze : versi�n inicial</li>
     * </ul></P>
     *
     * @param numeroOrigen : Anexo o n�mero de telefon�a fija en formato banco para el origen de la llamada.
     * @param numeroDestino : Anexo o n�mero de tlefon�a fija en formato banco para el origen de la llamada.
     * @param textoIntroduccion : Texto que se reproducir� al originador de la llamada antes de conectar al destinatario
     * @since 1.0
     */		
	public void llamadaTelefonicaConIntroduccion(TelefonoTO numeroOrigen, TelefonoTO numeroDestino, String textoIntroduccion)
	throws Exception
	{
		
	}
	
	public boolean reloadConfiguracion()
	{
		return AMI_Listener.reloadConfiguration(); 
	}
	
	public void cerrarConexion()
	{
		if (AMI_Listener.isRunning())
		{
			AMI_Listener.logoff();
		}
	}
}

